﻿namespace QuickMail.View.Controls
{
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Data.SQLite;
    using System.Diagnostics;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Input;
    using System.Windows.Markup;
    using System.Windows.Media;

    using QuickMail.BusinessLogic;
    using QuickMail.DataModels;
    using QuickMail.View.Windows;
    using DbWorker.AccessModels;
    using DbWorker.DataModels;
    using QuickMail.ViewModels;

    /// <summary>
    /// Form to display a tree of rules.
    /// </summary>
    public partial class RulesControl
    {
        #region Fields

        public readonly ObservableCollection<RuleVm> RuleVms = new ObservableCollection<RuleVm>();
        private RuleVm _selectedRuleVm;
        private bool _deletedRule;

        private readonly EnvironmentWorker _dirWorker = new EnvironmentWorker();
        private RuleAm _ruleAm;

        #endregion //End Fields

        public RulesControl()
        {
            InitializeComponent();
            SetCurrentTranslate();
        }

        /// <summary>
        /// Sets the current translation for form elements.
        /// </summary>
        public void SetCurrentTranslate()
        {
            PropertyTextBlock.Text = StaticFields.Lang.MainWindow.PropertyFolder.ToUpper();
            PropertyButton.ToolTip = StaticFields.Lang.MainWindow.PropertyFolderTt;
            DeleteButton.ToolTip = StaticFields.Lang.MainWindow.DeleteFolder;
            AddButton.ToolTip = StaticFields.Lang.MainWindow.AddFolder;

            AddMenuItem.Header = StaticFields.Lang.MainWindow.AddFolder;
            DeleteMenuItem.Header = StaticFields.Lang.MainWindow.DeleteFolder;
            PropertyMenuItem.Header = StaticFields.Lang.MainWindow.PropertyFolderTt;
            OpenFolderMenuItem.Header = StaticFields.Lang.MainWindow.OpenFolder;
        }

        /// <summary>
        /// Loading data models and creating view models
        /// </summary>
        public void Load()
        {
            List<RuleDm> mainRuleDms;
            _ruleAm = new RuleAm(StaticFields.DbConnection);
            _ruleAm.SelectMainRules(out mainRuleDms);

            foreach (var mainRule in mainRuleDms)
            {
                var ruleVm = new RuleVm(mainRule);
                GetSubrules(mainRule, ruleVm);
                RuleVms.Add(ruleVm);
            }

            RulesTreeView.ItemsSource = RuleVms;
        }

        #region Events of interface

        /// <summary>
        /// Change the selected rule in TreeView
        /// </summary>
        private void TreeView_OnSelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
        {
            _selectedRuleVm = RulesTreeView.SelectedItem as RuleVm;

            if (_selectedRuleVm == null)
            {
                PropertyButton.IsEnabled = DeleteButton.IsEnabled =
                    PropertyMenuItem.IsEnabled = DeleteMenuItem.IsEnabled =
                    OpenFolderMenuItem.IsEnabled = false;

                PropertyMenuItemImage.Opacity = DeleteMenuItemImage.Opacity = OpenFolderMenuItemImage.Opacity = 0.5;
            }
            else
            {
                PropertyButton.IsEnabled = DeleteButton.IsEnabled =
                    PropertyMenuItem.IsEnabled = DeleteMenuItem.IsEnabled =
                    OpenFolderMenuItem.IsEnabled = true;

                PropertyMenuItemImage.Opacity = DeleteMenuItemImage.Opacity = OpenFolderMenuItemImage.Opacity = 1;
            }
        }

        /// <summary>
        /// Add new rule
        /// </summary>
        private void AddButton_OnClick(object sender, RoutedEventArgs e)
        {
            var pw = new PropertyWindow();
            if (pw.ShowDialog() != true)
                return;

            if (pw.AddChildrensCheckBox.IsChecked == true)
            {
                _dirWorker.ResultScanDirs = true;
                if (!_dirWorker.RecursiveCreateRules(pw.CurrentRuleVm.DirectoryPath, pw.CurrentRuleVm))
                    return;
            }

            if (_selectedRuleVm == null)
            {
                if (_ruleAm.Insert(pw.CurrentRuleVm.CreateDataModel(), out pw.CurrentRuleVm.Id))
                {
                    SaveSubrules(pw.CurrentRuleVm);
                    RuleVms.Add(pw.CurrentRuleVm);
                }
            }
            else
            {
                pw.CurrentRuleVm.ParentId = _selectedRuleVm.Id;
                if (_ruleAm.Insert(pw.CurrentRuleVm.CreateDataModel(), out pw.CurrentRuleVm.Id))
                {
                    SaveSubrules(pw.CurrentRuleVm);
                    _selectedRuleVm.Childrens.Add(pw.CurrentRuleVm);
                }
            }
        }

        /// <summary>
        /// Removes the selected rule
        /// </summary>
        private void DeleteButton_OnClick(object sender, RoutedEventArgs e)
        {
            _ruleAm.Delete(_selectedRuleVm.Id);
            DeleteSubrules(_selectedRuleVm);

            if (!RuleVms.Remove(_selectedRuleVm))
            {
                foreach (var ruleVm in RuleVms)
                {
                    if (_deletedRule)
                        break;

                    RecursiveDeleteVm(ruleVm);
                }
            }

            _deletedRule = false;
        }

        /// <summary>
        /// Shows the properties of the selected rule
        /// </summary>
        private void PropertyButton_OnClick(object sender, RoutedEventArgs e)
        {
            var pw = new PropertyWindow(_selectedRuleVm);
            if (pw.ShowDialog() == true)
            {
                _ruleAm.Update(pw.CurrentRuleVm.CreateDataModel());
            }
        }

        /// <summary>
        /// Mouse right button down
        /// </summary>
        private void RulesTreeView_OnMouseRightButtonDown(object sender, MouseButtonEventArgs e)
        {
            TreeViewItem treeViewItem = VisualUpwardSearch(e.OriginalSource as DependencyObject);

            if (treeViewItem != null)
            {
                treeViewItem.Focus();
                e.Handled = true;
            }
        }

        /// <summary>
        /// Mouse left button down
        /// </summary>
        private void RulesTreeView_OnPreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            if (RulesTreeView != null && RulesTreeView.SelectedItem != null)
                RulesTreeView.ContainerFromItem(RulesTreeView.SelectedItem).IsSelected = false;
        }

        /// <summary>
        /// Opens a directory in Windows Explorer
        /// </summary>
        private void OpenFolderMenuItem_OnClick(object sender, RoutedEventArgs e)
        {
            Process.Start("explorer.exe", _selectedRuleVm.DirectoryPath);
        }

        #endregion // End Events of interface

        /// <summary>
        /// Recursively scans the rules and creates childrens
        /// </summary>
        private void GetSubrules(RuleDm parentRule, RuleVm ruleVm)
        {
            List<RuleDm> childrenRuleVms;
            _ruleAm.SelectSubrules(parentRule.Id, out childrenRuleVms);

            foreach (var childrenRuleVm in childrenRuleVms)
            {
                var childrenVm = new RuleVm(childrenRuleVm);
                ruleVm.Childrens.Add(childrenVm);
                GetSubrules(childrenRuleVm, childrenVm);
            }
        }

        /// <summary>
        /// Recursively scans childrens of RuleVm and save them.
        /// </summary>
        /// <param name="parentRuleVm"></param>
        private void SaveSubrules(RuleVm parentRuleVm)
        {
            foreach (var childrenRuleVm in parentRuleVm.Childrens)
            {
                childrenRuleVm.ParentId = parentRuleVm.Id;
                if (_ruleAm.Insert(childrenRuleVm.CreateDataModel(), out childrenRuleVm.Id))
                    SaveSubrules(childrenRuleVm);
            }
        }
        
        /// <summary>
        /// Recursively scans the rules and deletes all childrens
        /// </summary>
        private void DeleteSubrules(RuleVm parentRuleVm)
        {
            foreach (var childrenRuleVm in parentRuleVm.Childrens)
            {
                if (_ruleAm.Delete(childrenRuleVm.Id))
                    DeleteSubrules(childrenRuleVm);
            }
        }

        /// <summary>
        /// Recursively scans the rules and deletes the selected
        /// </summary>
        private void RecursiveDeleteVm(RuleVm parentFolder)
        {
            foreach (var children in parentFolder.Childrens)
            {
                if (children == _selectedRuleVm)
                {
                    parentFolder.Childrens.Remove(children);
                    _deletedRule = true;
                    return;
                }

                RecursiveDeleteVm(children);
            }
        }

        /// <summary>
        /// The visual upward search
        /// </summary>
        private TreeViewItem VisualUpwardSearch(DependencyObject source)
        {
            while (source != null && !(source is TreeViewItem))
                source = VisualTreeHelper.GetParent(source);

            return source as TreeViewItem;
        }
    }
}